package classloader;

import java.io.*;

/**
 * 自定义类加载器
 *
 * 问题点
 * 1.双亲委托机制 对类的加载
 * 2.加载器的命名空间
 */
public class MyTest16_1 extends ClassLoader {

    private String classLoaderName;

    private String path;

    public void setPath(String path) {
        this.path = path;
    }

    private static final String fileExtention = ".class";

    public MyTest16_1(ClassLoader parent, String classLoaderName) {
        super(parent);//显示指定该类的父类加载器
        this.classLoaderName = classLoaderName;
    }

    public MyTest16_1(String classLoaderName) {
        super();//将系统类加载器当作该类的父类加载器
        this.classLoaderName = classLoaderName;
    }

    public MyTest16_1(ClassLoader parent) {
        super(parent);//显示指定该类的父类加载器
    }

    @Override
    public Class findClass(String name) {
        System.out.println("findClass,输出这句话说明我们自己的类加载器加载了指定的类");
        System.out.println("class loader name :" + this.classLoaderName);
        byte[] b = loadClassData(name);
        return defineClass(name, b, 0, b.length);
    }

    private byte[] loadClassData(String name) {
        System.out.println("loadClassData  我们自定义的loadClassData读取class文件字节数组");
        InputStream is = null;
        byte[] data = null;
        ByteArrayOutputStream byteArrayOutputStream = null;

        try {
            name = name.replace(".", File.separator);//File.separator根据操作系统而变化
            is = new FileInputStream(new File(path + name + fileExtention));
            byteArrayOutputStream = new ByteArrayOutputStream();
            int len = 0;
            while (-1 != (len = is.read())) {
                byteArrayOutputStream.write(len);
            }
            data = byteArrayOutputStream.toByteArray();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
                byteArrayOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return data;
        }
    }


    public static void main(String[] args) throws Exception {
        //（此处测试建议把源码文件先删掉，不然idea会重新生成classes,还是会导致系统类加载器加载）

        MyTest16_1 loader1 = new MyTest16_1("load1");
        test1(loader1);
        MyTest16_1 loader2 = new MyTest16_1("load2");//load2又会加载一次  ---》加载器的命名空间
        test1(loader2);
        MyTest16_1 loader3 = new MyTest16_1(loader2,"load3");//这样就实现 把同一层次的加载器，变成双亲委托机制里的“父子关系”
        test1(loader3);
        MyTest16_1 Loader4 = new MyTest16_1(loader3,"load4");//双亲委托机制
        test1(Loader4);
        MyTest16_1 Loader5 = new MyTest16_1("Loader5");//load5又会加载一次  ---》加载器的命名空间
        test1(Loader5);

        /* 因为 loader2 = null; System.gc(); 把加载器卸载了，所以第二次又加载了
        执行结果：
findClass,输出这句话说明我们自己的类加载器加载了指定的类
class loader name :load1
loadClassData  我们自定义的loadClassData读取class文件字节数组
classloader.MyTest16_1@1b6d3586
1956725890
-------------------------------------
findClass,输出这句话说明我们自己的类加载器加载了指定的类
class loader name :load2
loadClassData  我们自定义的loadClassData读取class文件字节数组
classloader.MyTest16_1@1540e19d
21685669
-------------------------------------
classloader.MyTest16_1@1540e19d
2133927002
-------------------------------------
classloader.MyTest16_1@1540e19d
1836019240
-------------------------------------
findClass,输出这句话说明我们自己的类加载器加载了指定的类
class loader name :Loader5
loadClassData  我们自定义的loadClassData读取class文件字节数组
classloader.MyTest16_1@135fbaa4
856419764
-------------------------------------
        */
    }

    private static void test1(MyTest16_1 loader2) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        loader2.setPath("D:\\code\\class\\");
        Class<?> clazz = loader2.loadClass("classloader.MyTest1");
        Object instance = clazz.newInstance();
        System.out.println(instance.getClass().getClassLoader());
        System.out.println(instance.hashCode());
        System.out.println("-------------------------------------");
        //运行结果：（此处测试建议把源码文件先删掉，不然idea会重新生成classes,还是会导致系统类加载器加载）
    }
}
